﻿using Api.Commands;
using Api.Entitys;
using Core;
using Core.CommandProcesser;
using Core.Entities;
using Core.Enums;
using Core.Exceptions;
using Core.Formats;
using Core.Reader;
using Core.ReadWriter;
using Core.Tools;
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.IO;
using System.Web;

namespace Api
{
    /// <summary>
    /// CommonProcess 的摘要说明
    /// </summary>
    public class CommonProcess : BaseProcess, IHttpHandler
    {
        private static readonly EsonFormat EsonFormat;
        private static readonly JsonFormat JsonFormat;
        private static readonly XmlFormat XmlFormat;

        private static readonly CommandInfo ReadCommandByName;
        private static readonly CommandInfo ReadCommandParamsById;

        internal static readonly TSQLProcesser TSQLProcesserInstance;
        internal static readonly CSharpProcesser CSharpProcesserInstance;
        internal static readonly SystemProcesser SystemProcesserInstance;

        private static readonly AuthorizedUsers AuthorizedUsers;

        static CommonProcess()
        {
            EsonFormat = new EsonFormat();
            JsonFormat = new JsonFormat();
            XmlFormat = new XmlFormat();

            TSQLProcesserInstance = new TSQLProcesser("Data Source=.;Initial Catalog=Core;Persist Security Info=True;User ID=sa;Password=qq@19971218");

            TSQLProcesserInstance.AllowUnknownResultFiltering = true;

            CSharpProcesserInstance = new CSharpProcesser();
            SystemProcesserInstance = new SystemProcesser("Api");

            AddCommandProcesser("C#", CSharpProcesserInstance);
            AddCommandProcesser("T-SQL", TSQLProcesserInstance);
            AddCommandProcesser("System", SystemProcesserInstance);

            ReadCommandByName = new ReadCommandByName();
            ReadCommandParamsById = new ReadCommandParamsById();

            TSQLProcesserInstance.Initialization(ReadCommandByName);
            TSQLProcesserInstance.Initialization(ReadCommandParamsById);

            DefaultFormat = EsonFormat;

            AuthorizedUsers = new AuthorizedUsers();

            Logs.LogsDirectory = new DirectoryInfo("D://CoreLogs");
        }

        private int UserId;

        /// <summary>
        /// HttpContext
        /// </summary>
        public HttpContext Context { get; private set; }

        public UserInfo UserInfo
        {
            get
            {
                return AuthorizedUsers[UserId];
            }
        }


        public CommonProcess()
        {
        }

        public override void Finish(IDataReader Reader, TextWriter Writer)
        {
            if (FromCache)
            {
                HttpContext.Current.Response.Headers.Add("FromCache", "true");
            }

            base.Finish(Reader, Writer);
        }

        protected override ConfigInfo[] GetGlobalConfigs()
        {
            List<ConfigInfo> Result = new List<ConfigInfo>();

            ProcessCommand(GetCommand("ReadAllConfigs"), DataReader =>
            {
                while (DataReader.Read())
                {
                    ConfigInfo Item = new ConfigInfo();

                    Item.Name = Convert.ToString(DataReader["Name"]);
                    Item.Description = Convert.ToString(DataReader["Description"]);

                    object Value = DataReader["Value"];
                    ParamTypes Type = (ParamTypes)Convert.ToInt32(DataReader["Type"]);

                    try
                    {
                        Item.Value = TypeHelper.CastParameterType(Value, Type);
                    }
                    catch (Exception)
                    {
                        Logs.Exception(new ParamFormatException(string.Format("全局配置项 '{0}', 的定义类型 '{1}' 与实际值 '{2}' 不匹配。", Item.Name, Type, Value)));
                    }

                    Result.Add(Item);
                }
            });

            return Result.ToArray();
        }


        /// <summary> 系统请求入口，所有的 Server 请求都必须从这个入口进入，且系统未提供其他入口 </summary>
        public void ProcessRequest(HttpContext Context)
        {
            DateTime Begin = DateTime.Now;

            UserId = -1;

            this.Context = Context;

            Context.Response.ContentType = "text/plain";

            /* 解析参数 */
            using (StreamReader Reader = new StreamReader(Context.Request.InputStream, Context.Request.ContentEncoding))
            {
                var ParamsText = Reader.ReadToEnd();

                if (ParamsText.Length != 0)
                {
                    switch (Context.Request.ContentType)
                    {
                        case "Json":
                            JsonFormat.Decode(ParamsText, CreateParamsReadWriter());
                            break;
                        case "Xml":
                            XmlFormat.Decode(ParamsText, CreateParamsReadWriter());
                            break;
                        case "Eson":
                            EsonFormat.Decode(ParamsText, CreateParamsReadWriter());
                            break;
                        default:
                            CopyToParams(Context.Request.Form);
                            break;
                    }
                }
            }

            /* 复制 QueryString 参数 */
            CopyToParams(Context.Request.QueryString);

            /* 设置返回文档格式 */
            if (Format == null)
            {
                var ContextType = GetItem<string>("ContentType");

                switch (ContextType)
                {
                    case "Json":
                        Format = JsonFormat;
                        break;
                    case "Xml":
                        Format = XmlFormat;
                        break;
                    case "Eson":
                        Format = EsonFormat;
                        break;
                }
            }

            object ObjectUserId;

            /* 设置用户信息 */
            if (Params.TryGetValue("UserId", out ObjectUserId))
            {
                try
                {
                    UserId = Convert.ToInt32(ObjectUserId);

                    if (!AuthorizedUsers.IsAuthorized(UserId))
                    {
                        DoException(new Exception("UserId 无效！"));

                        return;
                    }

                    Guid Token;

                    object ObjectToken;

                    /* 设置会话 Token */
                    if (Params.TryGetValue("Token", out ObjectToken))
                    {
                        if (ObjectToken is Guid)
                        {
                            Token = (Guid)ObjectToken;
                        }
                        else if (!(ObjectToken is string && Guid.TryParse((string)ObjectToken, out Token)))
                        {
                            DoException(new Exception("Token 格式错误！"));

                            return;
                        }

                        if (UserInfo.Token != Token)
                        {
                            DoException(new Exception("Token 无效！"));

                            return;
                        }
                    }
                }
                catch (Exception)
                {
                    DoException(new Exception("UserId 格式错误！"));

                    return;
                }
            }

            try
            {
                /* 验证 Time 类型格式 */
                GetItem<DateTime>("Time");
            }
            catch (Exception e)
            {
                DoException(e);

                return;
            }

            /* 调用处理程序 */
            Process(Context.Response.Output);

            /* 移除 .Net 自带头 Server */
            Context.Response.Headers.Remove("Server");

            var UsedTime = DateTime.Now - Begin;

            Context.Response.Headers.Add("ProcessUsedTime", UsedTime.TotalMilliseconds.ToString());
        }

        /// <summary>
        /// 将 NameValueCollection 对象的元素 Copy 到 Params 中
        /// </summary>
        /// <param name="Source">NameValueCollection 对象</param>
        private void CopyToParams(NameValueCollection Source)
        {
            ArrayHelper.Each(Source, (Name, Value) =>
            {
                if (Name != null)
                {
                    Params.Add(Name, EsonFormat.ParseValue(Value));
                }

                return true;
            });
        }

        /// <summary>
        /// 处理异常
        /// </summary>
        /// <param name="e">异常信息</param>
        private void DoException(Exception e)
        {
            Context.Response.Headers.Remove("Server");

            ProcessException(e, Reader => {
                /* 处理异常处理结果 */
                Finish(Reader, Context.Response.Output);
            });
        }
        
        /// <summary>
        /// 通过命令名称获得命令信息
        /// </summary>
        /// <param name="CommandInfo">一个仅有命令名称的实例。</param>
        /// <returns>是否存在该命令</returns>
        protected override bool TryGetCommand(CommandInfo CommandInfo)
        {
            CommandInfo.Id = 0;

            Params.Add("Name", CommandInfo.Name);

            TSQLProcesserInstance.Process(this, ReadCommandByName, DataReader =>
            {
                if (DataReader.Read())
                {
                    CommandInfo.Id = Convert.ToInt32(DataReader["Id"]);
                    CommandInfo.Type = Convert.ToString(DataReader["Type"]);
                    CommandInfo.Code = Convert.ToString(DataReader["Code"]);
                    CommandInfo.Sign = (CommandSigns)Convert.ToInt32(DataReader["Sign"]);
                    CommandInfo.CacheToken = Convert.ToString(DataReader["CacheToken"]);
                    CommandInfo.Description = Convert.ToString(DataReader["Description"]);
                }
            });

            Params.RemoveLast("Name");

            if (CommandInfo.Id == 0)
            {
                return false;
            }

            Params.Add("CommandId", CommandInfo.Id);

            var CommandParams = new List<CommandParamInfo>();
            var CommandResults = new List<CommandParamInfo>();

            TSQLProcesserInstance.Process(this, ReadCommandParamsById, DataReader =>
            {
                while (DataReader.Read())
                {
                    var Item = new CommandParamInfo();

                    Item.Name = Convert.ToString(DataReader["Name"]);
                    Item.Type = (ParamTypes)Convert.ToInt32(DataReader["Type"]);
                    Item.Sign = (CommandParamSigns)Convert.ToInt32(DataReader["Sign"]);
                    Item.Description = Convert.ToString(DataReader["Description"]);

                    if (Convert.ToInt32(DataReader["InOut"]) == 1)
                    {
                        CommandParams.Add(Item);
                    }
                    else
                    {
                        CommandResults.Add(Item);
                    }
                }
            });

            Params.RemoveLast("CommandId");

            CommandInfo.Params = CommandParams.ToArray();
            CommandInfo.Results = CommandResults.ToArray();

            return true;
        }

        /// <summary>
        /// 检查命令授权
        /// </summary>
        /// <param name="CommandInfo">命令信息</param>
        public override void CheckCommand(CommandInfo CommandInfo)
        {
            if ((CommandInfo.Sign & CommandSigns.Authorize) != 0)
            {
                if (!AuthorizedUsers.IsAuthorized(UserId, CommandInfo.Id))
                {
                    throw new UnauthorizedException(CommandInfo.Name + " -- 未授权。");
                }
            }

            base.CheckCommand(CommandInfo);
        }

        /// <summary>
        /// 获得所有触发器
        /// </summary>
        /// <returns></returns>
        protected override TriggerInfo[] GetTriggers()
        {
            var Result = new List<TriggerInfo>();

            ProcessCommand(GetCommand("ReadAllTrigger"), (DataReader) =>
            {
                while (DataReader.Read())
                {
                    var CommandId = Convert.ToInt32(DataReader["CommandId"]);
                    var Sign = Convert.ToInt32(DataReader["Sign"]);
                    var Bind = Convert.ToInt32(DataReader["Bind"]);
                    var Name = Convert.ToString(DataReader["Name"]);
                    var Priority = Convert.ToInt32(DataReader["Priority"]);

                    Result.Add(new TriggerInfo() { Bind = Bind, CommandInfo = GetCommand(Name), Priority = Priority, Sign = (TriggerSigns)Sign });
                }
            });

            return Result.ToArray();
        }

        /// <summary> 允许重复使用 </summary>
        public bool IsReusable
        {
            get
            {
                return true;
            }
        }

        public override object this[string Key]
        {
            get 
            {
                switch (Key)
                {
                    case "Token":
                        return UserInfo.Token;
                    case "UserId":
                        return UserId;
                    case "UserName":
                        return UserInfo.UserName;
                    case "IP":
                        return Context.Request.UserHostAddress;
                    case "RequestUrl":
                        return Context.Request.Url.Scheme + "://" + Context.Request.Url.Authority + Context.Request.RawUrl;
                    case "RawUrl":
                        return Context.Request.RawUrl;
                    case "Time":
                        object Time = base[Key];

                        if (Time == null)
                        {
                            return null;
                        }

                        if (!(Time is DateTime))
                        {
                            Time = Convert.ToDateTime(Time);

                            Params["Time"] = Time;
                        }

                        return Time;
                    default:
                        return base[Key];
                }
            }
        }
    }
}